package com.aaa.web.util;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.*;
import java.util.*;

/**
 * @ fileName:BaseDao
 * @ description: 通用（基础）的JDBC封装工具类
 * @ author:李江波
 * @ createTime:2023/03/03 9:13
 * @ version:1.0.0
 */
public class BaseUtil {


//    //定义常量  常量不能被更改的
//    private final static String DRIVER_CLASS = "com.mysql.cj.jdbc.Driver";
//    private final static String URL = "jdbc:mysql://localhost:3306/db_qy164?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai";
//    private final static String USER_NAME = "root";
//    private final static String PASSWORD = "root";

    //数据源对象
    private static DataSource dataSource;
    /**
     * 静态匿名块   类被加载时执行，并且只执行一次
     */
    static {
        try {
            //读取配置文件
            InputStream inputStream = BaseUtil.class.getResourceAsStream("/db.properties");
            //实例化properties
            Properties properties = new Properties();
            //加载流，初始化properties
            properties.load(inputStream);
            //使用data工厂类创建dataSource对象
            dataSource = DruidDataSourceFactory.createDataSource(properties);
            //加载驱动类
            Class.forName(properties.getProperty("driverClassName"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取Connection
     * @return
     */
     public static Connection  getConnection(){
         Connection connection = null;
         try {
              //System.out.println(1/0);
              //connection = DriverManager.getConnection(URL, USER_NAME, PASSWORD);
             connection = dataSource.getConnection();
         } catch (Exception e) {
             e.printStackTrace();
         }
         return connection;
     }

    /**
     * 设置参数
     * @param preparedStatement
     * @param paramsArray
     */
     public static  void  setParams(PreparedStatement preparedStatement,Object[] paramsArray) throws SQLException {
         //判断参数数组是否为null
         if(paramsArray==null||paramsArray.length==0){
             // System.out.println("参数数组为空错误！");
              return;
         }
         //循环遍历
         for (int i = 0; i < paramsArray.length; i++) {
             //因为preparedStatement设置参数下标从1开始，循环数组的下标从0开始
             preparedStatement.setObject(i+1,paramsArray[i]);
         }
     }

    /**
     * 更新方法
     * @param sql  要执行更新的语句
     * @param params  需要的参数
     * @return
     */
     public static  int  executeUpdate(String sql,Object[] params){
           //调用封装方法获取Connection
           Connection connection = getConnection();
           PreparedStatement preparedStatement = null;
            //定义返回值
            int resultNum = 0;
             try {
                 //获取preparedStatement语句执行对象，并传入sql语句
                 preparedStatement = connection.prepareStatement(sql);
                 //调用封装方法获取参数
                 setParams(preparedStatement,params);
                 //执行更新,并返回执行成功条数
                 //return preparedStatement.executeUpdate();
                 resultNum = preparedStatement.executeUpdate();
             } catch (Exception e) {
                 e.printStackTrace();
             }finally {
                //关闭资源
                 closeAll(connection,preparedStatement,null);
             }
             //return 0;
             return resultNum;
     }


    /**
     * 执行查询
     * @param sql  要执行的语句
     * @param params  需要的参数  ... jdk5的新特性   相当于数组 但是数组输入必须参数，没有参数必须传null  使用...没有参数可以不传
     * @return
     */
     //public static List<Map>  executeQuery(String sql,Object... params,int... i){ //不能含有多个...
     //public static List<Map>  executeQuery(String sql,Object... params,int i){  //参数...必须放到最后
     public static List<Map>  executeQuery(String sql,Object... params){
        //调用封装类获取Connection
         Connection connection = getConnection();
         PreparedStatement preparedStatement = null;
         ResultSet resultSet = null;
         //定义返回结果集
         List<Map> returnMapList = new ArrayList<>();
         try {
             //获取语句执行对象，并传入sql
              preparedStatement = connection.prepareStatement(sql);
             //调用封装方法设置参数
             setParams(preparedStatement,params);
             //执行查询并返回结果集
             resultSet = preparedStatement.executeQuery();
             
             // 通过resultSet获取元数据对象
             ResultSetMetaData metaData = resultSet.getMetaData();
             //sql = select dept_no,dept_name,loc from tb_dept    columnCount = 3
             //sql = select `emp_id`, `emp_name`, `sex`, `phone_num`, `province`, `hire_date`, `dept_no`, `salary`, `password` from tb_dept    columnCount = 9
             //sql = select `emp_id`, `emp_name`, `sex`, `phone_num` from tb_goods   columnCount = 4
             //  ....    ....
             //sql = select *  from tables;    columnCount = count(column)
             // 动态获取执行语句的列的数量
             int columnCount = metaData.getColumnCount();

             //定义Map集合
             Map map = null;

             //循环结果集
             while (resultSet.next()){
                 //每循环一次都要实例化一个Map  把当前行的内容放入里面
                 map = new HashMap();
                 // dept_no dept_name loc
                 // 第1次 11     财务部1   郑州1
                 // 第2次 112    市场1部   开封1
                 // 第3次 113    市场2部   开封2
                 //  ....
                 //每循环一次，获取一行数据
                /* map.put(列名称, resultSet.getObject(1));
                 map.put(列名称, resultSet.getObject(2));
                 map.put(列名称, resultSet.getObject(3));
                 .....*/
                 //循环每行数据的列
                 for (int i = 1; i <= columnCount; i++) {
                      //每行列   第1次  dept_no   11
                     //          第2次  dept_name   财务部1
                     //          第3次  loc   郑州1
                     //根据下标获取列的名称
                     String columnName = metaData.getColumnName(i);
                     //根据下标获取列的数据
                     Object columnValue = resultSet.getObject(i);
                     //把列名称和值存入map
                     map.put(columnName,columnValue);
                 }
                 //把每行map放入返回集合
                 returnMapList.add(map);
             }

         } catch (Exception e) {
             e.printStackTrace();
         }finally {
             closeAll(connection,preparedStatement,resultSet);
         }
         return returnMapList;
     }

    /**
     * 关闭方法   后打开的先关闭
     * @param connection
     * @param statement
     * @param resultSet
     */
     public static void closeAll(Connection connection,Statement statement,ResultSet resultSet){
         try {
             if(resultSet!=null){
                 resultSet.close();
             }
         } catch (Exception e) {
             e.printStackTrace();
         }
         try {
             if(statement!=null){
                 statement.close();
             }
         } catch (Exception e) {
             e.printStackTrace();
         }
         try {
             if(connection!=null){
                 connection.close();
             }
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
}
